//
//  MsgRunLoopCtr.swift
//  sinaDemo
//
//  Created by admin on 2021/7/6.
// source1捕捉触摸事件，交给source0来处理
/*
 1. kCFRunLoopDefaultMode：App的默认Mode，通常主线程是在这个Mode下运行
 2. UITrackingRunLoopMode：界面跟踪 Mode，用于 ScrollView 追踪触摸滑动，保证界面滑动时不受其他 Mode 影响
 3. UIInitializationRunLoopMode: 在刚启动 App 时第进入的第一个 Mode，启动完成后就不再使用，会切换到kCFRunLoopDefaultMode
 4. GSEventReceiveRunLoopMode: 接受系统事件的内部 Mode，通常用不到
 5. kCFRunLoopCommonModes: 这是一个占位用的Mode，作为标记kCFRunLoopDefaultMode和UITrackingRunLoopMode用，并不是一种真正的Mode
 */
/*
    所有事件
    typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
    kCFRunLoopEntry = (1UL << 0),   //   即将进入RunLoop
    kCFRunLoopBeforeTimers = (1UL << 1), // 即将处理Timer
    kCFRunLoopBeforeSources = (1UL << 2), // 即将处理Source
    kCFRunLoopBeforeWaiting = (1UL << 5), //即将进入休眠
    kCFRunLoopAfterWaiting = (1UL << 6),// 刚从休眠中唤醒
    kCFRunLoopExit = (1UL << 7),// 即将退出RunLoop
    kCFRunLoopAllActivities = 0x0FFFFFFFU
    };
    */

/*
 struct __CFRunLoop {
     CFRuntimeBase _base;
     pthread_mutex_t _lock;            /* locked for accessing mode list */
     __CFPort _wakeUpPort;            // used for CFRunLoopWakeUp
     Boolean _unused;
     volatile _per_run_data *_perRunData;              // reset for runs of the run loop
     pthread_t _pthread; //runloop所在的线程 每一个runloop对应一个线程
     uint32_t _winthread;
     CFMutableSetRef _commonModes; // 存储commonMode中的mode 默认commonMode 中含有两个mode
     CFMutableSetRef _commonModeItems; //存储commonModelItem中的(source, observer, timer)
     CFRunLoopModeRef _currentMode; //runloop当前所在的mode
     CFMutableSetRef _modes; //__CFRunLoopMode 一个线程中存在多个mode
     struct _block_item *_blocks_head;
     struct _block_item *_blocks_tail;
     CFTypeRef _counterpart;
 };
 */
import UIKit
class XMThread: Thread {
    deinit {
        print(XMThread.self,#function)
    }
}
// 定义一个类实现 NSPortDelegate 协议
class PortHandler: NSObject, PortDelegate {

    func handle(_ message: Any) {
        if let messageData = (message as AnyObject).value(forKey: "msg") as? String {
            print("Received message: \(messageData)")
        }
    }
}
class MsgRunLoopCtr: UIViewController {
    lazy var xmThreadStoped = false
    lazy var xmThread:XMThread = XMThread.init {[weak self] in
        //用block就防止了循环引用
        print("--thread begin--")
        //如不使用runloop保活，那么执行完block内代码线程就死了。
        //这个方法将一个 Port 对象添加到当前线程的 RunLoop 中，以便使其能够接收来自其他线程或进程的消息。
        //Port 主要用于线程之间的通信，可以理解为它是一个消息队列（消息管道）。当你使用 Port 时，另一个线程可以向该端口发送消息，当前线程的 RunLoop 会接收到这些消息并处理。
        // 1. 创建 Port 对象
        let port1 = Port()
        RunLoop.current.add(port1, forMode: .default)
        // 2. 设置代理
//        let portHandler = PortHandler()
//        port1.setDelegate(portHandler)
        
        //run()函数内部实现是while循环
        //RunLoop.current.run()
        //（如果使用c语言的CFRunloop runmode 的话就不再需要stoped了），因为CFRunloop run的时候有个参数用来标记执行完source0就退出当前runloop
        while let stoped = self?.xmThreadStoped {
            if !stoped {
                //此函数真正的用来睡眠线程（睡眠并非是一直循环从而阻塞线程，而是内核区调用内核API--》mach_msg方法来使其休眠）。默认执行完source0就会退出当前runloop
                RunLoop.current.run(mode: .default, before: .distantFuture)
            }
        }
        // 这里可以直接处理来自 Port 的消息
        // ...
        //停止runloop与stop函数内的CFRunLoopStop方法有相同效果
//        RunLoop.current.run(mode: .default, before: .distantPast)
        print("--thread end--")
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .white
        title = "runloop"
        xmThread.start()
        // Do any additional setup after loading the view.
    }
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        perform(#selector(self.threadDoSomeThing), on: xmThread, with: nil, waitUntilDone: false)
        print("touchesBegan")
    }
    @objc private func threadDoSomeThing() {
        print(Thread.current,"threadDoSomeThings")
    }
    @objc private func threadStop() {
        print("threadStop")
        self.xmThreadStoped = true
        //停止runloop
        CFRunLoopStop(CFRunLoopGetCurrent())
    }
    deinit{
        print(MsgRunLoopCtr.self,#function)
        perform(#selector(self.threadStop), on: xmThread, with: nil, waitUntilDone: true)
    }
}
